package tij4.concurrent.source;

/*
    Exchanger是在两个任务之间交换对象的栅栏.
    当这些任务进入栅栏时,它们各自拥有一个对象,
    当它们离开时,它们都拥有之前由对象持有对象.

    Exchanger可以在两个线程之间交换数据，只能是2个线程，他不支持更多的线程之间互换数据。

    当线程A调用Exchange对象的exchange()方法后，他会陷入阻塞状态，直到线程B也调用了exchange()方法，
    然后以线程安全的方式交换数据，之后线程A和B继续运行
 */

import tij4.concurrent.util.BasicGenerator;
import tij4.concurrent.util.Generator;

import java.util.List;
import java.util.concurrent.*;

class ExchangerProducer<T> implements Runnable {
    private Generator<T> generator;
    private Exchanger<List<T>> exchanger;
    private List<T> holder;

    public ExchangerProducer(Exchanger<List<T>> exchanger, Generator<T> generator, List<T> holder) {
        this.generator = generator;
        this.exchanger = exchanger;
        this.holder = holder;
    }

    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                for (int i = 0; i < ExChangerDemo.size; i++) {
                    holder.add(generator.next());
                }
                holder = exchanger.exchange(holder);
            }
        }catch (InterruptedException e) {

        }
    }
}

class ExchangerConsumer<T> implements Runnable {
    private Exchanger<List<T>> exchanger;
    private List<T> holder;
    private volatile T value;

    public ExchangerConsumer(Exchanger<List<T>> exchanger, List<T> holder) {
        this.exchanger = exchanger;
        this.holder = holder;
    }

    @Override
    public void run() {
        try{
            while (!Thread.interrupted()) {
                holder = exchanger.exchange(holder);
                for (T x : holder) {
                    value = x;
                    holder.remove(x);
                }
            }
        }catch (InterruptedException e) {

        }
        System.out.println("Final value: " + value);
    }
}

class ExchangerConsumer1<T> implements Runnable {
    private Exchanger<List<T>> exchanger;
    private List<T> holder;
    private volatile T value;

    public ExchangerConsumer1(Exchanger<List<T>> exchanger, List<T> holder) {
        this.exchanger = exchanger;
        this.holder = holder;
    }

    @Override
    public void run() {
        try{
            while (!Thread.interrupted()) {
                holder = exchanger.exchange(holder);
                for (T x : holder) {
                    value = x;
                    holder.remove(x);
                }
            }
        }catch (InterruptedException e) {

        }
        System.out.println("Final value: " + value);
    }
}

public class ExChangerDemo {
    static int size = 10;
    static int delay = 5;

    public static void main(String[] args) throws Exception{
        ExecutorService executorService = Executors.newCachedThreadPool();
        Exchanger<List<Fat>> listExchanger = new Exchanger<>();
        List<Fat>
                producerList = new CopyOnWriteArrayList<>(),
                consumerList = new CopyOnWriteArrayList<>();
        executorService.execute(new ExchangerProducer<Fat>(listExchanger,
                BasicGenerator.create(Fat.class), producerList));
        executorService.execute(new ExchangerConsumer<Fat>(listExchanger, consumerList));
        //没有报错,只是Fat id 的值变小了
//        executorService.execute(new ExchangerConsumer1<Fat>(listExchanger, consumerList));
        TimeUnit.SECONDS.sleep(delay);
        executorService.shutdownNow();
    }

}
